//
//  AudioConvertSwift.swift
//  GLUZSwift
//
//  Created by xyanl on 2025/4/26.
//
//  音频格式转换
import Foundation
import AVFoundation

class AudioConvertSwift {
    
    static func convertLowQualityM4aToMp3(m4aPath: String, mp3Path: String, completion: @escaping (Bool) -> Void) {
        DispatchQueue.global(qos: .default).async {
            do {
                // 输入文件
                let m4aUrl = URL(fileURLWithPath: m4aPath)
                let asset = AVURLAsset(url: m4aUrl)
                
                // 读取音频数据
                let reader = try AVAssetReader(asset: asset)
                
                // 获取音频轨道
                guard let track = asset.tracks(withMediaType: .audio).first else {
                    print("No audio track found")
                    DispatchQueue.main.async { completion(false) }
                    return
                }
                
                // 音频输出设置 - 适配8000Hz单声道
                let outputSettings: [String: Any] = [
                    AVFormatIDKey: kAudioFormatLinearPCM,
                    AVLinearPCMBitDepthKey: 16,
                    AVLinearPCMIsBigEndianKey: false,
                    AVLinearPCMIsFloatKey: false,
                    AVLinearPCMIsNonInterleaved: false,
                    AVSampleRateKey: 8000.0,
                    AVNumberOfChannelsKey: 1
                ]
                
                let trackOutput = AVAssetReaderTrackOutput(track: track, outputSettings: outputSettings)
                reader.add(trackOutput)
                reader.startReading()
                
                // 准备输出MP3文件
                guard let mp3File = fopen(mp3Path, "wb") else {
                    print("Could not create MP3 file")
                    DispatchQueue.main.async { completion(false) }
                    return
                }
                
                // 初始化LAME - 适配8000Hz单声道
                let lame = lame_init()
                lame_set_in_samplerate(lame, 8000)   // 设置输入采样率
                lame_set_num_channels(lame, 1)       // 单声道
                lame_set_mode(lame, MONO)             // 设置为单声道模式
                lame_set_quality(lame, 5)            // 中等质量
                lame_set_brate(lame, 16)             // 设置比特率为16kbps
                lame_set_VBR(lame, vbr_off)          // 关闭VBR，使用CBR
                
                lame_init_params(lame)
                
                // 缓冲区
                // let PCM_SIZE = 8192
                let MP3_SIZE = 8192
                // var pcm_buffer = [Int16](repeating: 0, count: PCM_SIZE)
                var mp3_buffer = [UInt8](repeating: 0, count: MP3_SIZE)
                
                // 转换过程
                while reader.status == .reading {
                    if let sampleBuffer = trackOutput.copyNextSampleBuffer() {
                        let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer)!
                        let bufferLength = CMBlockBufferGetDataLength(blockBuffer)
                        
                        if bufferLength > 0 {
                            var data = Data(count: bufferLength)
                            CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: bufferLength, destination: data.withUnsafeMutableBytes { $0.baseAddress! })
                            
                            // 转换为PCM数据
                            let bytes = data.withUnsafeBytes { $0.bindMemory(to: Int16.self) }
                            let numSamples = bufferLength / MemoryLayout<Int16>.size
                            
                            // 写入LAME进行编码（单声道使用lame_encode_buffer）
                            let bytesWritten = lame_encode_buffer(lame, UnsafeMutablePointer(mutating: bytes.baseAddress!), nil, Int32(numSamples), &mp3_buffer, Int32(MP3_SIZE))
                            fwrite(&mp3_buffer, Int(bytesWritten), 1, mp3File)
                        }
                        
                        CMSampleBufferInvalidate(sampleBuffer)
                    }
                }
                
                // 写入剩余数据
                let bytesWritten = lame_encode_flush(lame, &mp3_buffer, Int32(MP3_SIZE))
                if bytesWritten > 0 {
                    fwrite(&mp3_buffer, Int(bytesWritten), 1, mp3File)
                }
                
                // 清理资源
                lame_close(lame)
                fclose(mp3File)
                
                DispatchQueue.main.async { completion(true) }
            } catch {
                print("Conversion failed: \(error.localizedDescription)")
                DispatchQueue.main.async { completion(false) }
            }
        }
    }
    
    /// 将远程音频 (mp3/m4a) 转换为 wav (16kHz, PCM)
        /// - Parameters:
        ///   - url: 远程音频 URL
        ///   - completion: 转换完成回调，返回本地 wav 文件 URL 或错误
        static func convertToWav(from url: URL, completion: @escaping (Result<URL, Error>) -> Void) {
            // 先下载远程文件到临时目录
            let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + "." + url.pathExtension)
            
            URLSession.shared.downloadTask(with: url) { localURL, _, error in
                if let error = error {
                    completion(.failure(error))
                    return
                }
                guard let localURL = localURL else {
                    completion(.failure(NSError(domain: "AudioConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "下载失败"])))
                    return
                }
                
                do {
                    try FileManager.default.moveItem(at: localURL, to: tempFile)
                    AudioConvertSwift().transcodeToWav(inputURL: tempFile, completion: completion)
                } catch {
                    completion(.failure(error))
                }
            }.resume()
        }
        
    private var reader: AVAssetReader?
    private var readerOutput: AVAssetReaderTrackOutput?
    private var writer: AVAssetWriter?
    private var writerInput: AVAssetWriterInput?
    private var outputURL: URL?
    
    func transcodeToWav(inputURL: URL, completion: @escaping (Result<URL, Error>) -> Void) {
            let asset = AVURLAsset(url: inputURL)
            
            guard let audioTrack = asset.tracks(withMediaType: .audio).first else {
                completion(.failure(NSError(domain: "AudioConverter", code: -2, userInfo: [NSLocalizedDescriptionKey: "没有音频轨道"])))
                return
            }
            
            let outURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString + ".wav")
            self.outputURL = outURL
            
            do {
                // reader
                let reader = try AVAssetReader(asset: asset)
                let readerOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: [
                    AVFormatIDKey: kAudioFormatLinearPCM,
                    AVSampleRateKey: 16000,
                    AVNumberOfChannelsKey: 1,
                    AVLinearPCMBitDepthKey: 16,
                    AVLinearPCMIsNonInterleaved: false,
                    AVLinearPCMIsFloatKey: false,
                    AVLinearPCMIsBigEndianKey: false
                ])
                
                guard reader.canAdd(readerOutput) else {
                    completion(.failure(NSError(domain: "AudioConverter", code: -10, userInfo: [NSLocalizedDescriptionKey: "reader 无法添加 output"])))
                    return
                }
                reader.add(readerOutput)
                
                // writer
                let writer = try AVAssetWriter(outputURL: outURL, fileType: .wav)
                let writerInput = AVAssetWriterInput(mediaType: .audio, outputSettings: [
                    AVFormatIDKey: kAudioFormatLinearPCM,
                    AVSampleRateKey: 16000,
                    AVNumberOfChannelsKey: 1,
                    AVLinearPCMBitDepthKey: 16,
                    AVLinearPCMIsNonInterleaved: false,
                    AVLinearPCMIsFloatKey: false,
                    AVLinearPCMIsBigEndianKey: false
                ])
                
                guard writer.canAdd(writerInput) else {
                    completion(.failure(NSError(domain: "AudioConverter", code: -11, userInfo: [NSLocalizedDescriptionKey: "writer 无法添加 input"])))
                    return
                }
                writer.add(writerInput)
                
                // 强引用保存到实例属性，避免闭包释放
                self.reader = reader
                self.readerOutput = readerOutput
                self.writer = writer
                self.writerInput = writerInput
                
                writer.startWriting()
                writer.startSession(atSourceTime: .zero)
                reader.startReading()
                
                let queue = DispatchQueue(label: "audio.convert.queue")
                writerInput.requestMediaDataWhenReady(on: queue) { 
                    
                    
                    while writerInput.isReadyForMoreMediaData {
                        if let sampleBuffer = self.readerOutput?.copyNextSampleBuffer() {
                            writerInput.append(sampleBuffer)
                        } else {
                            writerInput.markAsFinished()
                            writer.finishWriting {
                                if writer.status == .completed {
                                    completion(.success(outURL))
                                } else {
                                    completion(.failure(writer.error ?? NSError(domain: "AudioConverter", code: -3, userInfo: [NSLocalizedDescriptionKey: "写入失败"])))
                                }
                            }
                            break
                        }
                    }
                }
                
            } catch {
                completion(.failure(error))
            }
        }
    
    
    /// 将本地 mp3 转换为裸 PCM 文件，返回输出路径
    static func convertMP3ToRawPCM(mp3Path: String) throws -> String {
        // 检查输入文件是否存在
        guard FileManager.default.fileExists(atPath: mp3Path) else {
            throw NSError(domain: "PCMConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "音频文件不存在"])
        }
        
        let mp3URL = URL(fileURLWithPath: mp3Path)
        
        // 输出文件路径 (临时目录)
        let pcmURL = FileManager.default.temporaryDirectory.appendingPathComponent("output.pcm")
        
        // 如果已有文件，先删除
        if FileManager.default.fileExists(atPath: pcmURL.path) {
            try FileManager.default.removeItem(at: pcmURL)
        }
        
        let asset = AVAsset(url: mp3URL)
        
        // 检查asset是否可读
        guard asset.isReadable else {
            throw NSError(domain: "PCMConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "音频文件不可读"])
        }
        
        // 检查音频时长
        let duration = CMTimeGetSeconds(asset.duration)
        guard duration > 0 else {
            throw NSError(domain: "PCMConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "音频文件时长为0"])
        }
        
        guard let reader = try? AVAssetReader(asset: asset) else {
            throw NSError(domain: "PCMConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法创建 AVAssetReader"])
        }
        
        guard let track = asset.tracks(withMediaType: .audio).first else {
            throw NSError(domain: "PCMConverter", code: -2, userInfo: [NSLocalizedDescriptionKey: "未找到音频轨道"])
        }
        
        // 输出格式: 16bit PCM, little-endian, 16K采样率, 单声道
        let outputSettings: [String: Any] = [
            AVFormatIDKey: kAudioFormatLinearPCM,
            AVLinearPCMBitDepthKey: 16,
            AVLinearPCMIsFloatKey: false,
            AVLinearPCMIsBigEndianKey: false,
            AVLinearPCMIsNonInterleaved: false,
            AVSampleRateKey: 16000.0,  // 16K采样率
            AVNumberOfChannelsKey: 1   // 单声道
        ]
        
        let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: outputSettings)
        reader.add(readerOutput)
        
        guard reader.startReading() else {
            throw NSError(domain: "PCMConverter", code: -3, userInfo: [NSLocalizedDescriptionKey: "无法开始读取"])
        }
        
        // 输出文件写入
        FileManager.default.createFile(atPath: pcmURL.path, contents: nil, attributes: nil)
        guard let fileHandle = try? FileHandle(forWritingTo: pcmURL) else {
            throw NSError(domain: "PCMConverter", code: -4, userInfo: [NSLocalizedDescriptionKey: "无法创建输出文件"])
        }
        
        defer {
            try? fileHandle.close()
        }
        
        // 循环读取并写入裸 PCM 数据
        while let sampleBuffer = readerOutput.copyNextSampleBuffer() {
            if let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
                var length = 0
                var dataPointer: UnsafeMutablePointer<Int8>?
                if CMBlockBufferGetDataPointer(blockBuffer, atOffset: 0, lengthAtOffsetOut: nil, totalLengthOut: &length, dataPointerOut: &dataPointer) == noErr {
                    if let baseAddress = dataPointer {
                        let data = Data(bytes: baseAddress, count: length)
                        try fileHandle.write(contentsOf: data)
                    }
                }
            }
        }
        
        if reader.status == .completed {
            return pcmURL.path
        } else {
            throw reader.error ?? NSError(domain: "PCMConverter", code: -5, userInfo: [NSLocalizedDescriptionKey: "未知错误"])
        }
    }
    
    
    
    static func convertAACToPCM(aacPath: String) throws -> String {
        let aacURL = URL(fileURLWithPath: aacPath)
        
        // 输出路径（临时目录下）
        let pcmURL = FileManager.default.temporaryDirectory.appendingPathComponent("output.pcm")
        
        // 如果已有同名文件，先删除
        if FileManager.default.fileExists(atPath: pcmURL.path) {
            try FileManager.default.removeItem(at: pcmURL)
        }
        
        let asset = AVAsset(url: aacURL)
        guard let reader = try? AVAssetReader(asset: asset) else {
            throw NSError(domain: "PCMConverter", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法创建 AVAssetReader"])
        }
        
        guard let track = asset.tracks(withMediaType: .audio).first else {
            throw NSError(domain: "PCMConverter", code: -2, userInfo: [NSLocalizedDescriptionKey: "未找到音频轨道"])
        }
        
        // 输出设置为 PCM
        // 输出格式: 16bit PCM, little-endian, 16K采样率, 单声道
        let outputSettings: [String: Any] = [
            AVFormatIDKey: kAudioFormatLinearPCM,
            AVLinearPCMBitDepthKey: 16,
            AVLinearPCMIsFloatKey: false,
            AVLinearPCMIsBigEndianKey: false,
            AVLinearPCMIsNonInterleaved: false,
            AVSampleRateKey: 16000.0,  // 16K采样率
            AVNumberOfChannelsKey: 1   // 单声道
        ]
        
        let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: outputSettings)
        reader.add(readerOutput)
        
        guard reader.startReading() else {
            throw NSError(domain: "PCMConverter", code: -3, userInfo: [NSLocalizedDescriptionKey: "无法开始读取"])
        }
        
        // 创建输出文件
        FileManager.default.createFile(atPath: pcmURL.path, contents: nil, attributes: nil)
        guard let fileHandle = try? FileHandle(forWritingTo: pcmURL) else {
            throw NSError(domain: "PCMConverter", code: -4, userInfo: [NSLocalizedDescriptionKey: "无法创建输出文件"])
        }
        
        defer {
            try? fileHandle.close()
        }
        
        // 循环解码 AAC → PCM
        while let sampleBuffer = readerOutput.copyNextSampleBuffer() {
            if let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
                var length = 0
                var dataPointer: UnsafeMutablePointer<Int8>?
                
                if CMBlockBufferGetDataPointer(blockBuffer,
                                               atOffset: 0,
                                               lengthAtOffsetOut: nil,
                                               totalLengthOut: &length,
                                               dataPointerOut: &dataPointer) == noErr {
                    if let baseAddress = dataPointer {
                        let data = Data(bytes: baseAddress, count: length)
                        try fileHandle.write(contentsOf: data)
                    }
                }
            }
        }
        
        if reader.status == .completed {
            return pcmURL.path
        } else {
            throw reader.error ?? NSError(domain: "PCMConverter", code: -5, userInfo: [NSLocalizedDescriptionKey: "未知错误"])
        }
    }
}
